
#include "rc.h"
#include <string.h>
#include <stdio.h>

#define UART_RC             UART_NUM_1
#define BUF_SIZE (1024)
#define RD_BUF_SIZE (BUF_SIZE)

static const char *TAG = "rc";
rc_t rc;

// static QueueHandle_t uart_rc_queue;
uint8_t uart_rc_buffer[10];
rc_t rc2;   //注意资源互斥使用！最好加个mutex

void parse_rc(uint8_t *buf, uint16_t len)
{
    if (len < 10 || buf[0] != 0xff || buf[1] != 0x5a) {
        return ;
    }
    uint8_t sum = 0;
    for (int i=2; i<=8; ++i) {
        sum += buf[i];
    }
    if (sum != buf[9]) {
        return ;    //checksum failed
        //TODO: when failed many times. we need reset uart.
    }

    memcpy(&rc, &buf[2], sizeof(rc));
    static int logcnt;
    if (logcnt++ >= 5) 
    {
        logcnt = 0;
        ESP_LOGI(TAG, "ch [%3d %3d %3d %3d]", rc.lx, rc.ly, rc.rx, rc.ry);
    }
    // ESP_LOGI(TAG, "dir[%d %d %d %d]", rc.UP, rc.DOWN, rc.LEFT, rc.RIGHT);
}

// static void rc_decode_task(void *pvParameters)
// {
//     uart_event_t event;
//     uint8_t* dtmp = (uint8_t*) malloc(RD_BUF_SIZE);
//     for(;;) {
//         //Waiting for UART event.
//         if(xQueueReceive(uart_rc_queue, (void * )&event, (portTickType)portMAX_DELAY)) {
//             switch(event.type) {
//                 /*We'd better handler data event fast, there would be much more data events than
//                 other types of events. If we take too much time on data event, the queue might
//                 be full.*/
//                 case UART_DATA:
//                     // ESP_LOGI(TAG, "[UART DATA]: %d", event.size);
//                     if (event.size == 10) {
//                         uart_read_bytes(UART_RC, uart_rc_buffer, event.size, portMAX_DELAY);
//                         parse_rc(uart_rc_buffer, event.size);
//                         memcpy(&rc2, &rc, sizeof(rc));
//                     }
//                     // ESP_LOGI(TAG, "[DATA EVT]:");
//                     // uart_write_bytes(UART_RC, (const char*) dtmp, event.size);
//                     break;
//                 case UART_FIFO_OVF:
//                     ESP_LOGI(TAG, "hw fifo overflow");
//                     // If fifo overflow happened, you should consider adding flow control for your application.
//                     // The ISR has already reset the rx FIFO,
//                     // As an example, we directly flush the rx buffer here in order to read more data.
//                     uart_flush_input(UART_RC);
//                     xQueueReset(uart_rc_queue);
//                     break;
//                 case UART_BUFFER_FULL:
//                     ESP_LOGI(TAG, "ring buffer full");
//                     // If buffer full happened, you should consider encreasing your buffer size
//                     // As an example, we directly flush the rx buffer here in order to read more data.
//                     uart_flush_input(UART_RC);
//                     xQueueReset(uart_rc_queue);
//                     break;
//                 case UART_BREAK:
//                     ESP_LOGI(TAG, "uart rx break");
//                     break;
//                 case UART_PARITY_ERR:
//                     ESP_LOGI(TAG, "uart parity error");
//                     break;
//                 case UART_FRAME_ERR:
//                     ESP_LOGI(TAG, "uart frame error");
//                     break;
//                 default:
//                     ESP_LOGI(TAG, "uart event type: %d", event.type);
//                     break;
//             }
//         }
//     }
//     free(dtmp); //we will never go here.
//     dtmp = NULL;
//     vTaskDelete(NULL);
// }


void rc_init(void)
{
    /* Configure parameters of an UART driver,
     * communication pins and install the driver */
    uart_config_t uart_config = {
        .baud_rate = 115200,
        .data_bits = UART_DATA_8_BITS,
        .parity = UART_PARITY_DISABLE,
        .stop_bits = UART_STOP_BITS_1,
        .flow_ctrl = UART_HW_FLOWCTRL_DISABLE,
        .source_clk = UART_SCLK_APB,
    };

    uart_driver_install(UART_RC, BUF_SIZE * 2, BUF_SIZE * 2, 10, &uart_rc_queue, 0);
    uart_param_config(UART_RC, &uart_config);

    //Set UART log level
    esp_log_level_set(TAG, ESP_LOG_INFO);
    //Set UART pins (using UART0 default pins ie no changes.)
    uart_set_pin(UART_RC, UART_RC_TX_IO, UART_RC_RX_IO, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE);

    //Create a task to handler URAT event from ISR
    xTaskCreate(rc_decode_task, "rc_decode_task", 2048, NULL, 12, NULL);
}


// Include MicroPython API.
#include "py/runtime.h"

//添加import rc 相关支持
// This is the function which will be called from Python as rc.
STATIC mp_obj_t rc_channels() {
    // Extract the ints from the micropython input objects.
    // int ly = mp_obj_get_int(g_obj);
    // int rx = mp_obj_get_int(b_obj);
    // int ry = mp_obj_get_int(b_obj);

    mp_obj_t tuple[] = {
        MP_OBJ_NEW_SMALL_INT(rc2.lx),
        MP_OBJ_NEW_SMALL_INT(rc2.ly),
        MP_OBJ_NEW_SMALL_INT(rc2.rx),
        MP_OBJ_NEW_SMALL_INT(rc2.ry),
    };

    // convert to MicroPython object.
    return mp_obj_new_tuple(4, tuple);
}

STATIC mp_obj_t rc_keys() {
    mp_obj_t tuple[] = {
        MP_OBJ_NEW_SMALL_INT(rc2.R1),
        MP_OBJ_NEW_SMALL_INT(rc2.R2),
        MP_OBJ_NEW_SMALL_INT(rc2.R3),
        MP_OBJ_NEW_SMALL_INT(rc2.L1),
        MP_OBJ_NEW_SMALL_INT(rc2.L3),
        MP_OBJ_NEW_SMALL_INT(rc2.BT),
        MP_OBJ_NEW_SMALL_INT(rc2.A),
        MP_OBJ_NEW_SMALL_INT(rc2.B),
        MP_OBJ_NEW_SMALL_INT(rc2.X),
        MP_OBJ_NEW_SMALL_INT(rc2.Y),
        MP_OBJ_NEW_SMALL_INT(rc2.POWER),
        MP_OBJ_NEW_SMALL_INT(rc2.START),
    };

    // convert to MicroPython object.
    return mp_obj_new_tuple(12, tuple);
}

STATIC mp_obj_t rc_dirs() {
    mp_obj_t tuple[] = {
        MP_OBJ_NEW_SMALL_INT(rc2.UP),
        MP_OBJ_NEW_SMALL_INT(rc2.DOWN),
        MP_OBJ_NEW_SMALL_INT(rc2.LEFT),
        MP_OBJ_NEW_SMALL_INT(rc2.RIGHT),
    };

    // convert to MicroPython object.
    return mp_obj_new_tuple(4, tuple);
}

STATIC mp_obj_t rc_A() {
    return MP_OBJ_NEW_SMALL_INT(rc2.A);
}

STATIC mp_obj_t rc_B() {
    return MP_OBJ_NEW_SMALL_INT(rc2.B);
}

// Define a Python reference to the function above.
STATIC MP_DEFINE_CONST_FUN_OBJ_0(rc_channels_obj, rc_channels);
STATIC MP_DEFINE_CONST_FUN_OBJ_0(rc_keys_obj, rc_keys);
STATIC MP_DEFINE_CONST_FUN_OBJ_0(rc_dirs_obj, rc_dirs);
STATIC MP_DEFINE_CONST_FUN_OBJ_0(rc_A_obj, rc_A);
STATIC MP_DEFINE_CONST_FUN_OBJ_0(rc_B_obj, rc_B);

// Define all properties of the module.
// Table entries are key/value pairs of the attribute name (a string)
// and the MicroPython object reference.
// All identifiers and strings are written as MP_QSTR_xxx and will be
// optimized to word-sized integers by the build system (interned strings).
STATIC const mp_rom_map_elem_t rc_module_globals_table[] = {
    { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_rc) },
    { MP_ROM_QSTR(MP_QSTR_channels), MP_ROM_PTR(&rc_channels_obj) },
    { MP_ROM_QSTR(MP_QSTR_keys), MP_ROM_PTR(&rc_keys_obj) },
    { MP_ROM_QSTR(MP_QSTR_dirs), MP_ROM_PTR(&rc_dirs_obj) },
    { MP_ROM_QSTR(MP_QSTR_A), MP_ROM_PTR(&rc_A_obj) },
    { MP_ROM_QSTR(MP_QSTR_B), MP_ROM_PTR(&rc_B_obj) },
};
STATIC MP_DEFINE_CONST_DICT(rc_module_globals, rc_module_globals_table);

// Define module object.
const mp_obj_module_t rc_user_cmodule = {
    .base = { &mp_type_module },
    .globals = (mp_obj_dict_t *)&rc_module_globals,
};

// Register the module to make it available in Python.
// Note: the "1" in the third argument means this module is always enabled.
// This "1" can be optionally replaced with a macro like MODULE_CEXAMPLE_ENABLED
// which can then be used to conditionally enable this module.
MP_REGISTER_MODULE(MP_QSTR_rc, rc_user_cmodule, 1);